package io.keen.client.java;

import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

public class FileEventStore implements KeenEventStore {
    private final File root;

    public FileEventStore(File root) throws IOException {
        if (root.exists() && root.isDirectory()) {
            this.root = root;
            return;
        }
        throw new IOException("Event store root '" + root + "' must exist and be a directory");
    }

    public Object store(String projectId, String eventCollection, String event) throws IOException {
        Throwable th;
        File cacheFile = getFileForEvent(prepareCollectionDir(projectId, eventCollection), Calendar.getInstance());
        Writer writer = null;
        try {
            Writer writer2 = new OutputStreamWriter(new FileOutputStream(cacheFile), "UTF-8");
            try {
                writer2.write(event);
                KeenUtils.closeQuietly(writer2);
                return cacheFile;
            } catch (Throwable th2) {
                th = th2;
                writer = writer2;
                KeenUtils.closeQuietly(writer);
                throw th;
            }
        } catch (Throwable th3) {
            th = th3;
            KeenUtils.closeQuietly(writer);
            throw th;
        }
    }

    public String get(Object handle) throws IOException {
        if (handle instanceof File) {
            File eventFile = (File) handle;
            if (eventFile.exists() && eventFile.isFile()) {
                return KeenUtils.convertFileToString(eventFile);
            }
            return null;
        }
        throw new IllegalArgumentException("Expected File, but was " + handle.getClass());
    }

    public void remove(Object handle) throws IOException {
        if (handle instanceof File) {
            File eventFile = (File) handle;
            if (!eventFile.exists() || !eventFile.isFile()) {
                KeenLogging.log(String.format(Locale.US, "WARNING: no event found at %s", new Object[]{eventFile.getAbsolutePath()}));
                return;
            } else if (eventFile.delete()) {
                KeenLogging.log(String.format(Locale.US, "Successfully deleted file: %s", new Object[]{eventFile.getAbsolutePath()}));
                return;
            } else {
                KeenLogging.log(String.format(Locale.US, "CRITICAL ERROR: Could not remove event at %s", new Object[]{eventFile.getAbsolutePath()}));
                return;
            }
        }
        throw new IllegalArgumentException("Expected File, but was " + handle.getClass());
    }

    public Map<String, List<Object>> getHandles(String projectId) throws IOException {
        File projectDir = getProjectDir(projectId, false);
        if (projectDir.exists() && projectDir.isDirectory()) {
            return getHandlesFromProjectDirectory(projectDir);
        }
        return new HashMap();
    }

    private Map<String, List<Object>> getHandlesFromProjectDirectory(File projectDir) throws IOException {
        File[] collectionDirs = getSubDirectories(projectDir);
        Map<String, List<Object>> handleMap = new HashMap();
        if (collectionDirs != null) {
            for (File directory : collectionDirs) {
                String collectionName = directory.getName();
                File[] files = getFilesInDir(directory);
                if (files != null) {
                    List<Object> handleList = new ArrayList();
                    handleList.addAll(Arrays.asList(files));
                    handleMap.put(collectionName, handleList);
                } else {
                    KeenLogging.log("Directory was null while getting event handles: " + collectionName);
                }
            }
        }
        return handleMap;
    }

    private File getKeenCacheDirectory() throws IOException {
        File file = new File(this.root, "keen");
        if (file.exists() || file.mkdir()) {
            return file;
        }
        throw new IOException("Could not make keen cache directory at: " + file.getAbsolutePath());
    }

    private File[] getSubDirectories(File parent) throws IOException {
        return parent.listFiles(new FileFilter() {
            public boolean accept(File file) {
                return file.isDirectory();
            }
        });
    }

    private File[] getFilesInDir(File dir) {
        return dir.listFiles(new FileFilter() {
            public boolean accept(File file) {
                return file.isFile();
            }
        });
    }

    private File getProjectDir(String projectId, boolean create) throws IOException {
        File projectDir = new File(getKeenCacheDirectory(), projectId);
        if (create && !projectDir.exists()) {
            KeenLogging.log("Cache directory for project '" + projectId + "' doesn't exist. " + "Creating it.");
            if (!projectDir.mkdirs()) {
                throw new IOException("Could not create project cache directory '" + projectDir.getAbsolutePath() + "'");
            }
        }
        return projectDir;
    }

    private File getCollectionDir(String projectId, String eventCollection) throws IOException {
        File collectionDir = new File(getProjectDir(projectId, true), eventCollection);
        if (!collectionDir.exists()) {
            KeenLogging.log("Cache directory for event collection '" + eventCollection + "' doesn't exist. Creating it.");
            if (!collectionDir.mkdirs()) {
                throw new IOException("Could not create collection cache directory '" + collectionDir.getAbsolutePath() + "'");
            }
        }
        return collectionDir;
    }

    private File getFileForEvent(File collectionDir, Calendar timestamp) throws IOException {
        int counter = 0;
        File eventFile = getNextFileForEvent(collectionDir, timestamp, 0);
        while (eventFile.exists()) {
            eventFile = getNextFileForEvent(collectionDir, timestamp, counter);
            counter++;
        }
        return eventFile;
    }

    private File getNextFileForEvent(File dir, Calendar timestamp, int counter) {
        return new File(dir, Long.toString(timestamp.getTimeInMillis()) + "." + counter);
    }

    private int getMaxEventsPerCollection() {
        return 10000;
    }

    private int getNumberEventsToForget() {
        return 100;
    }

    private File prepareCollectionDir(String projectId, String eventCollection) throws IOException {
        File collectionDir = getCollectionDir(projectId, eventCollection);
        File[] eventFiles = getFilesInDir(collectionDir);
        if (eventFiles.length >= getMaxEventsPerCollection()) {
            KeenLogging.log(String.format(Locale.US, "Too many events in cache for %s, aging out old data", new Object[]{eventCollection}));
            KeenLogging.log(String.format(Locale.US, "Count: %d and Max: %d", new Object[]{Integer.valueOf(eventFiles.length), Integer.valueOf(getMaxEventsPerCollection())}));
            List<File> fileList = Arrays.asList(eventFiles);
            Collections.sort(fileList, new Comparator<File>() {
                public int compare(File file, File file1) {
                    return file.getAbsolutePath().compareToIgnoreCase(file1.getAbsolutePath());
                }
            });
            for (int i = 0; i < getNumberEventsToForget(); i++) {
                if (!((File) fileList.get(i)).delete()) {
                    KeenLogging.log(String.format(Locale.US, "CRITICAL: can't delete file %s, cache is going to be too big", new Object[]{((File) fileList.get(i)).getAbsolutePath()}));
                }
            }
        }
        return collectionDir;
    }
}
